package com.teatrace.webservice;



import java.util.HashMap;
import java.util.Map;

import javax.xml.ws.Endpoint;

import org.apache.cxf.jaxws.spring.EndpointDefinitionParser.SpringEndpointImpl;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class WSController {
	
	public static class ServiceState {
		public static final int PUBLISHED = 1;
		
		public static final int STARTED = 2;
		
		public static final int STOPED = 4;
		
		public static final int INIT = 0;
		
	}
	
	private static Logger log = Logger.getLogger(WSController.class);
	
	public static final int RUNNING = 1;
	
	public static final int DESTROYED = 2;
	
	public static final int NEW = 3;

	private static WSController instance;
	
	private Integer state = NEW;
	
	private ApplicationContext context;
	
	private Map<String, Integer> serviceStateMap = new HashMap<String, Integer>();
	
	public static WSController getInstance() {
		if(instance == null) {
			instance = new WSController();
		}
		return instance;
	}
	
	public void startService(String beanName) {
		startServices(new String[]{beanName});
	}
	
	public void startServices(String[] beanNames) {
		if(state == RUNNING) {
			for(String beanName : beanNames) {
				Object obj = context.getBean(beanName);
				if(!(obj instanceof Endpoint)) {
					throw new IllegalArgumentException("bean:" + beanName + " isn't a instance of class javax.xml.ws.Endpoint");
				}
				SpringEndpointImpl endpoint = (SpringEndpointImpl) obj;
				if(!endpoint.isPublished()) {
					endpoint.publish();
					this.addServiceState(beanName, ServiceState.PUBLISHED);
					if(log.isInfoEnabled()) {
						log.info("publish: " + beanName);
					}
				}
				endpoint.getServer().start();
				this.addServiceState(beanName, ServiceState.STARTED);
				this.deleteServiceState(beanName, ServiceState.STOPED);
				if(log.isDebugEnabled()) {
					log.info("start: " + beanName);
				}
				
			}
		} else {
			throw new IllegalStateException("state:" + state);
		}
	}
	
	public void stopService(String beanName) {
		this.stopServices(new String[] {beanName});
	}
	
	public void stopServices(String[] beanNames) {
		if(state == RUNNING) {
			for(String beanName : beanNames) {
				Object obj = context.getBean(beanName);
				if(!(obj instanceof Endpoint)) {
					throw new IllegalArgumentException("bean:" + beanName + " isn't a instance of class javax.xml.ws.Endpoint");
				}
				SpringEndpointImpl endpoint = (SpringEndpointImpl) obj;
				endpoint.getServer().stop();
				this.addServiceState(beanName, ServiceState.STOPED);
				this.deleteServiceState(beanName, ServiceState.STARTED);
				if(log.isDebugEnabled()) {
					log.info("stoped: " + beanName);
				}
				
			}
		} else {
			throw new IllegalStateException("state:" + state);
		}
	}
	
	public void stopAllService() {
		if(state == RUNNING) {
			for(String beanName : context.getBeanNamesForType(Endpoint.class)) {
				Object obj = context.getBean(beanName);
				if(!(obj instanceof Endpoint)) {
					throw new IllegalArgumentException("bean:" + beanName + " isn't a instance of class javax.xml.ws.Endpoint");
				}
				SpringEndpointImpl endpoint = (SpringEndpointImpl) obj;
				if(endpoint.isPublished()) {
					endpoint.getServer().stop();
					this.addServiceState(beanName, ServiceState.STOPED);
					this.deleteServiceState(beanName, ServiceState.STARTED);
					if(log.isDebugEnabled()) {
						log.info("stoped endpoint: " + beanName);
					}
				}
			}
		} else {
			throw new IllegalStateException("state:" + state);
		}
	}
	
	public void distroyInstance() {
		synchronized (state) {
			instance = null;
			state = DESTROYED;
		}
	}
	
	public boolean stopable(String beanName) {
		boolean flag = false;
		int state = getWebServiceState(beanName);
		if((state & ServiceState.STARTED) == ServiceState.STARTED) {
			flag = true;
		}
		return flag;
	}
	
	public boolean startable(String beanName) {
		boolean flag = true;
		int state = getWebServiceState(beanName);
		if((state & ServiceState.INIT) != ServiceState.INIT) {
			flag = false;
		}
		if((state & ServiceState.PUBLISHED) != ServiceState.PUBLISHED) {
			flag = false;
		}
		if((state & ServiceState.STARTED) == ServiceState.STARTED) {
			flag = false;
		}
		return flag;
	}
	
	public int getWebServiceState(String beanName) {
		return serviceStateMap.get(beanName);
	}
	
	private WSController() {
		serviceStateMap.put("antiFakeWS", ServiceState.INIT);
		serviceStateMap.put("rfidDataSyncWS", ServiceState.INIT);
		serviceStateMap.put("traceWS", ServiceState.INIT);
		serviceStateMap.put("mobilePlatformWS", ServiceState.INIT);
		this.init();
		this.stopAllService();
		this.addServiceState("antiFakeWS", ServiceState.PUBLISHED);
		this.addServiceState("rfidDataSyncWS", ServiceState.PUBLISHED);
		this.addServiceState("traceWS", ServiceState.PUBLISHED);
		this.addServiceState("mobilePlatformWS", ServiceState.PUBLISHED);
	}
	
	private void addServiceState(String beanName, int astate) {
		int state = serviceStateMap.get(beanName);
		state = astate | state;
		serviceStateMap.put(beanName, state);
	}
	
	private void deleteServiceState(String beanName, int astate) {
		int state = serviceStateMap.get(beanName);
		state = (~astate) & state;
		serviceStateMap.put(beanName, state);
	}
	
	private void init() {
		synchronized (state) {
			if(NEW == state) {
				context = new ClassPathXmlApplicationContext("spring-webservice.xml");
				state = RUNNING;
			}
		}
	}
}
